"""
添加一个神经层
"""

import tensorflow.compat.v1 as tf
import numpy as np
import matplotlib.pyplot as plt

# 在Tensorflow 2.0 中，eager execution 是默认开启的。所以，需要先关闭eager execution
tf.compat.v1.disable_eager_execution()


def add_layer(inputs, in_size, out_size, activation_func=None):
    # 创建一个参数，值为一个由随机数构成的 行为 in_size，列为out_size 的矩阵
    Weights = tf.Variable(tf.random_normal([in_size, out_size]))
    # 创建一个 1*out_size shape的矩阵，然后 + 0.1
    biases = tf.Variable(tf.zeros([1, out_size]) + 0.1)
    # 矩阵乘 input Weight 然后 + biases
    Wx_plus_b = tf.matmul(inputs, Weights) + biases

    # 如果不存在激活函数，输出线性结果
    if activation_func is None:
        outputs = Wx_plus_b
    else:
        # 否则，激活激励函数
        outputs = activation_func(Wx_plus_b)
    return outputs


x_data = np.linspace(-1, 1, 300)[:, np.newaxis]
# 一个均值为0的，概论分布标准差为0.05的，输出shape为300,1的正态分布随机矩阵
noise = np.random.normal(0, 0.05, x_data.shape)
y_data = np.square(x_data) - 0.5 + noise

xs = tf.placeholder(tf.float32, [None, 1])  # None表示第一个维度有多少个元素都可以
ys = tf.placeholder(tf.float32, [None, 1])
# 输入xs , 1 ？ ，设置10个神经元，激励函数为relu函数
l1 = add_layer(xs, 1, 10, activation_func=tf.nn.relu)  # 隐藏层
# 预测值
prediction = add_layer(l1, 10, 1, activation_func=None)  # 输出层

# ys - predication 真实数据与预测值相减
# square 平方
# reduce_sum 累加 reduction_indices = axis 表示 纵/横坐标轴（维度）的意思
# reduce_mean 求平均
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - prediction), reduction_indices=[1]))

# 使用梯度下降的优化器减少loss误差
train_step = tf.train.GradientDescentOptimizer(0.1).minimize(loss)

# 通用流程
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.scatter(x_data, y_data)  # 画出真实数据的点

plt.ion()  # 使下面的show方法不阻塞
plt.show()

for i in range(1000):
    sess.run(train_step, feed_dict={xs: x_data, ys: y_data})
    if i % 50 == 0:
        # 每训练50次，打印loss值，可以看到误差值越来越小
        print(sess.run(loss, feed_dict={xs: x_data, ys: y_data}))
        try:
            # 擦掉线
            ax.lines.remove(lines[0])
        except Exception:
            pass
        # 获取当前的学习出来的预测值
        prediction_value = sess.run(prediction, feed_dict={xs: x_data})
        # 画一条宽度为5 的代表预测值曲线的红线
        lines = ax.plot(x_data, prediction_value, '-r', lw=5)

        plt.pause(0.5)  # 暂停0.1s

